#include "pg_school.h"

/*
    根据列的类型，将对应的值转换成对应类型的DATUM
*/

Datum get_datum_by_col_type(AttrNumber col_type, char *new_value) {
    Datum update_value;
    switch (col_type) {
        case 1: // is_adult
            update_value = BoolGetDatum(strcmp(new_value, "t") == 0);
            break;
        case 2: // id
            update_value = Int64GetDatum(atoll(new_value));
            break;
        case 3: // phone
            update_value = Int64GetDatum(atoll(new_value));
            break;
        case 4: // name
            update_value = CStringGetTextDatum(new_value);
            break;
        case 5: // address
            update_value = CStringGetTextDatum(new_value);
            break;
        case 6: // INT
            update_value = Int32GetDatum(atoi(new_value));
            break;
        default:
            elog(ERROR,"Invalid column type: %d", col_type);
            break;
    }

    return update_value;
}


// 判断指定列或联合两列的值是否存在于表中
bool check_value_exists(Relation rel, 
                        char *update_col1_name, char *new_value1, 
                        char *update_col2_name, char *new_value2, 
                        char *table_name) {
    bool exists = false;
    ScanKeyData scanKey[2];  // 使用两个 ScanKey，以支持最多两列的判断
    SysScanDesc scanDesc = NULL;
    HeapTuple tuple = NULL;
    StrategyNumber strategy1, strategy2;
    RegProcedure procedure1, procedure2;
    Datum key_value1, key_value2;
    int numKeys = 0;

    // 获取第1列的索引和类型
    AttrNumber update_col1_index = 0;
    int update_col1_type = 0;
    get_index_type_bycolname(table_name, update_col1_name, &update_col1_type, &update_col1_index);

    // 获取第1列的扫描参数
    get_scan_key_params(update_col1_type, "=", &strategy1, &procedure1);
    key_value1 = get_datum_by_col_type(update_col1_type, new_value1);
    ScanKeyInit(&scanKey[0], update_col1_index, strategy1, procedure1, key_value1);
    numKeys++;  // 至少有一个键

    // 如果传入了第二列，获取第二列的索引和类型，设置第二个 ScanKey
    if (update_col2_name != NULL && new_value2 != NULL) {
        AttrNumber update_col2_index = 0;
        int update_col2_type = 0;

        get_index_type_bycolname(table_name, update_col2_name, &update_col2_type, &update_col2_index);
        get_scan_key_params(update_col2_type, "=", &strategy2, &procedure2);
        key_value2 = get_datum_by_col_type(update_col2_type, new_value2);
        ScanKeyInit(&scanKey[1], update_col2_index, strategy2, procedure2, key_value2);
        numKeys++;  // 增加第二个键
    }

    // 根据传入的键数量执行扫描
    scanDesc = systable_beginscan(rel, InvalidOid, false, NULL, numKeys, scanKey);
    while ((tuple = systable_getnext(scanDesc)) != NULL) {
        exists = true;
    }
    systable_endscan(scanDesc);

    if (exists) {
        if (numKeys == 1) {
           elog(WARNING, "COLUMN %s VALUE:%s already exists, cancel operation", update_col1_name, new_value1);
        } else if (numKeys == 2) {
            elog(WARNING, "Combination of COLUMN %s VALUE:%s and COLUMN %s VALUE:%s already exists, cancel operation",
                 update_col1_name, new_value1, update_col2_name, new_value2);
        }
    }

    return exists;
}

/*
    func:get_scan_key_params
    col_type_oid:列号
    cmp_operator：比较符号
    strategy：策略
    procedure：计划
*/
void get_scan_key_params(int16 col_type_oid, char *cmp_operator,
                          StrategyNumber *strategy, RegProcedure *procedure) {
    if (col_type_oid == SMALLINT) {
        *strategy = BTEqualStrategyNumber; // 可以根据需要更改策略
        if (strcmp(cmp_operator, "=") == 0) {
            *procedure = F_INT2EQ;
        } else if (strcmp(cmp_operator, "<") == 0) {
            *procedure = F_INT2LT;
            *strategy = BTLessStrategyNumber;
        } else if (strcmp(cmp_operator, ">") == 0) {
            *procedure = F_INT2GT;
            *strategy = BTGreaterStrategyNumber;
        } else {
            ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 
                            errmsg("Unsupported comparison operator for INT4: %s", cmp_operator)));
        }
    } else if (col_type_oid == INT) {
        *strategy = BTEqualStrategyNumber; // 可以根据需要更改策略
        if (strcmp(cmp_operator, "=") == 0) {
            *procedure = F_INT4EQ;
        } else if (strcmp(cmp_operator, "<") == 0) {
            *procedure = F_INT4LT;
            *strategy = BTLessStrategyNumber;
        } else if (strcmp(cmp_operator, ">") == 0) {
            *procedure = F_INT4GT;
            *strategy = BTGreaterStrategyNumber;
        } else {
            ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 
                            errmsg("Unsupported comparison operator for INT8: %s", cmp_operator)));
        }
    } else if (col_type_oid == BIGINT) {
        *strategy = BTEqualStrategyNumber; // 可以根据需要更改策略
        if (strcmp(cmp_operator, "=") == 0) {
            *procedure = F_INT8EQ;
        } else if (strcmp(cmp_operator, "<") == 0) {
            *procedure = F_INT8LT;
            *strategy = BTLessStrategyNumber;
        } else if (strcmp(cmp_operator, ">") == 0) {
            *procedure = F_INT8GT;
            *strategy = BTGreaterStrategyNumber;
        } else {
            ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 
                            errmsg("Unsupported comparison operator for INT8: %s", cmp_operator)));
        }
    } else if (col_type_oid == BOOLEAN) {
        *strategy = BTEqualStrategyNumber; // 布尔类型只支持等于
        if (strcmp(cmp_operator, "=") == 0) {
            *procedure = F_BOOLEQ;
        } else {
            ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 
                            errmsg("Unsupported comparison operator for BOOLEAN: %s", cmp_operator)));
        }
    } else if (col_type_oid == TEXT || col_type_oid == VARCHAR) {
        *strategy = BTEqualStrategyNumber; // 文本类型只支持等于
        if (strcmp(cmp_operator, "=") == 0) {
            *procedure = F_TEXTEQ;
        } else {
            ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 
                            errmsg("Unsupported comparison operator for TEXT: %s", cmp_operator)));
        }
    } else {
        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 
                        errmsg("Unsupported column type")));
    }
}


/*
    根据列名获取对应的列号
*/

AttrNumber get_column_index(char *table_name, char *col_name) {
    AttrNumber col_index = 0;

    /* 针对 changjunhighschool.student 表 */
    if (strcmp(table_name, "student") == 0) {
        if (strcmp(col_name, "is_adult") == 0) {
            col_index = Anum_changjunhighschool_student_is_adult;
        } else if (strcmp(col_name, "id") == 0) {
            col_index = Anum_changjunhighschool_student_id;
        } else if (strcmp(col_name, "phone") == 0) {
            col_index = Anum_changjunhighschool_student_phone;
        } else if (strcmp(col_name, "name") == 0) {
            col_index = Anum_changjunhighschool_student_name;
        } else if (strcmp(col_name, "address") == 0) {
            col_index = Anum_changjunhighschool_student_address;
        } else {
            ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Invalid column name for student: %s", col_name)));
        }

    /* 针对 changjunhighschool.score 表 */
    } else if (strcmp(table_name, "score") == 0) {
        if (strcmp(col_name, "chinese_score") == 0) {
            col_index = Anum_changjunhighschool_score_chinese_score;
        } else if (strcmp(col_name, "math_score") == 0) {
            col_index = Anum_changjunhighschool_score_math_score;
        } else if (strcmp(col_name, "evaluate") == 0) {
            col_index = Anum_changjunhighschool_score_evaluate;
        } else if (strcmp(col_name, "id") == 0) {
            col_index = Anum_changjunhighschool_score_id;  // 这里改为 score 表的 id
        } else if (strcmp(col_name, "ranking") == 0) {
            col_index = Anum_changjunhighschool_score_ranking;
        } else {
            ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Invalid column name for score: %s", col_name)));
        }
    } else {
        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Invalid table name: %s", table_name)));
    }

    return col_index;
}


/*
    根据列名获取对应的列类型
*/
int get_column_type(char *col_name) {
    int col_type = 0;
    if (strcmp(col_name, "is_adult") == 0) {
        col_type = BOOLEAN;
    } else if (strcmp(col_name, "id") == 0) {
        col_type = SMALLINT;
    } else if (strcmp(col_name, "phone") == 0 || strcmp(col_name, "ranking") == 0) {
        col_type = BIGINT;
    } else if (strcmp(col_name, "name") == 0 || strcmp(col_name, "evaluate") == 0) {
        col_type = VARCHAR;
    } else if (strcmp(col_name, "address") == 0) {
        col_type = TEXT;
    } else if (strcmp(col_name, "chinese_score") == 0 || strcmp(col_name, "math_score") == 0) {
        col_type = INT;
    }else {
        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Invalid column name: %s", col_name)));
    }
    
    return col_type;
}


void get_index_type_bycolname(char *tablename, char* col_name, int *col_type, AttrNumber* col_index)
{
    if (strcmp(col_name, "is_adult") == 0) {
        *col_type = BOOLEAN;
    } else if (strcmp(col_name, "id") == 0) {
        *col_type = SMALLINT;
    } else if (strcmp(col_name, "phone") == 0 || strcmp(col_name, "ranking") == 0) {
        *col_type = BIGINT;
    } else if (strcmp(col_name, "name") == 0 || strcmp(col_name, "evaluate") == 0) {
        *col_type = VARCHAR;
    } else if (strcmp(col_name, "address") == 0) {
        *col_type = TEXT;
    } else if (strcmp(col_name, "chinese_score") == 0 || strcmp(col_name, "math_score") == 0) {
        *col_type = INT;
    }else {
        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Invalid column name: %s", col_name)));
    }

    
    if (strcmp(col_name, "is_adult") == 0 || strcmp(col_name, "chinese_score") == 0) {
        *col_index = 1;
    } else if ((strcmp(col_name, "id") == 0 && strcmp(tablename, "student") == 0)
                    || strcmp(col_name, "math_score") == 0) {
        *col_index = 2;
    } else if (strcmp(col_name, "phone") == 0 || strcmp(col_name, "evaluate") == 0) {
        *col_index = 3;
    } else if (strcmp(col_name, "name") == 0 || strcmp(col_name, "id") == 0) {
        *col_index = 4;
    } else if (strcmp(col_name, "address") == 0 || strcmp(col_name, "ranking") == 0) {
        *col_index = 5;
    } else {
        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Invalid column name: %s", col_name)));
    }
    
}

Oid get_indexOID(char *col_name)
{
    Oid indexOID = 0;
    //使用索引扫描
    if (strcmp(col_name, "phone") == 0)
    {
        // 获取索引
        indexOID = get_relname_relid("idx_phone", get_namespace_oid(SCHEMANAME, true)); // 假设我们使用 phone 的索引
        if (!OidIsValid(indexOID)) {
            elog(WARNING, "No index found for column %s. Performing a full table scan.", col_name);
        }
    }else if(strcmp(col_name, "id") == 0){
        indexOID = get_relname_relid("student_pkey", get_namespace_oid(SCHEMANAME, true)); // 假设我们使用 phone 的索引
        if (!OidIsValid(indexOID)) {
            elog(WARNING, "No index found for column %s. Performing a full table scan.", col_name);
        }
    }else{
        elog(WARNING, "No index found for column %s. Performing a full table scan.", col_name);
    }
    return indexOID;
}